package com.share.device.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.share.common.core.exception.ServiceException;
import com.share.common.security.utils.SecurityUtils;
import com.share.device.domain.Cabinet;
import com.share.device.domain.Station;
import com.share.device.domain.StationLocation;
import com.share.device.feign.FeeRuleFeignService;
import com.share.device.mapper.CabinetMapper;
import com.share.device.mapper.StationMapper;
import com.share.device.repository.StationLocationRepository;
import com.share.device.service.IRegionService;
import com.share.device.service.IStationService;
import com.share.rule.domain.FeeRule;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author ZhouShuang
 * @version 17
 * @Title
 * @date 2025/10/11 下午5:07
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class StationServiceImpl extends ServiceImpl<StationMapper, Station> implements IStationService {

    private final StationMapper stationMapper;
    private final CabinetMapper cabinetMapper;
    private final IRegionService regionService;
    private final StationLocationRepository stationLocationRepository;
    private final FeeRuleFeignService feeRuleFeignService;

    /**
     * 查询站点列表
     *
     * @param station
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<Station> selectStationList(Station station) {
        List<Station> stationList = stationMapper.selectStationList(station);
        Set<Long> cabinetIds = stationList.stream()
                .map(Station::getCabinetId) // 获取所有站点的柜机id
                .filter(Objects::nonNull) // 过滤掉null
                .collect(Collectors.toSet()); // 转换成set, 去重
        Map<Long, String> cabinetNoMap; // 创建一个map, key为cabinetId, value为cabinetNo
        if (!CollectionUtils.isEmpty(cabinetIds)) { // 如果cabinetIds不为空
            List<Cabinet> cabinetList = cabinetMapper.selectList(new LambdaQueryWrapper<Cabinet>().in(Cabinet::getId, cabinetIds)); // 根据cabinetIds查询所有柜机信息
            cabinetNoMap = cabinetList.stream()
                    .collect(Collectors.toMap(Cabinet::getId, Cabinet::getCabinetNo, (key1, key2) -> key1));
        } else {
            cabinetNoMap = new HashMap<>();
        }
        List<FeeRule> feeRules = feeRuleFeignService.getALLFeeRuleList().getData();
        Map<Long, String> feeRuleMap = feeRules.stream().collect(Collectors.toMap(FeeRule::getId, FeeRule::getName, (key1, key2) -> key1));
        stationList.forEach(item -> {
            item.setCabinetNo(cabinetNoMap.getOrDefault(item.getCabinetId(), ""));// 给每个站点设置cabinetNo
            item.setFeeRuleName(feeRuleMap.getOrDefault(item.getFeeRuleId(), ""));// 给每个站点设置feeRuleName
        });
        return stationList;
    }

    /**
     * 添加站点
     *
     * @param station
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int saveStation(Station station) {
        String province = regionService.getNameByCode(station.getProvinceCode());
        String city = regionService.getNameByCode(station.getCityCode());
        String district = regionService.getNameByCode(station.getDistrictCode());
        station.setFullAddress(province + city + district + station.getAddress());

        StationLocation stationLocation = new StationLocation();
        stationLocation.setId(ObjectId.get().toString());
        stationLocation.setStationId(station.getId());
        stationLocation.setLocation(new GeoJsonPoint(station.getLongitude().doubleValue(), station.getLatitude().doubleValue()));
        stationLocation.setCreateTime(new Date());
        stationLocationRepository.save(stationLocation);
        return stationMapper.insert(station);
    }

    /**
     * 修改站点信息
     *
     * @param station
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateStation(Station station) {
        String province = regionService.getNameByCode(station.getProvinceCode());
        String city = regionService.getNameByCode(station.getCityCode());
        String district = regionService.getNameByCode(station.getDistrictCode());
        station.setFullAddress(province + city + district + station.getAddress());

        //同步信息到mongodb
        StationLocation stationLocation = stationLocationRepository.getByStationId(station.getId());
        stationLocation.setLocation(new GeoJsonPoint(station.getLongitude().doubleValue(), station.getLatitude().doubleValue()));
        stationLocationRepository.save(stationLocation);
        return stationMapper.updateById(station);
    }

    /**
     * 站点设置关联数据
     *
     * @param station
     * @return
     */
    @Override
    public int setData(Station station) {
        this.updateById(station);

        //更新柜机使用状态
        Cabinet cabinet = cabinetMapper.selectById(station.getCabinetId());
        cabinet.setStatus("1");
        return cabinetMapper.updateById(cabinet);
    }

    /**
     * 更新数据到mongodb
     */
    @Override
    public void updateData() {
        List<Station> stationList = this.list();
        stationList.forEach(item -> {
            StationLocation stationLocation = stationLocationRepository.getByStationId(item.getId());
            if (stationLocation == null) {
                stationLocation = new StationLocation();
                stationLocation.setId(ObjectId.get().toString());
                stationLocation.setStationId(item.getId());
                stationLocation.setLocation(new GeoJsonPoint(item.getLongitude().doubleValue(), item.getLatitude().doubleValue()));
                stationLocation.setCreateTime(new Date());
                stationLocationRepository.save(stationLocation);
            }
        });
    }

    /**
     * 删除站点信息
     *
     * @param ids
     * @return
     */
    @Override
    public int removeStationBatchByIds(List<Long> ids) {
        ids.forEach(stationLocationRepository::deleteByStationId);
        return stationMapper.deleteBatchIds(ids);
    }

    /**
     * 修改站点状态
     *
     * @param id
     * @param status
     * @return
     */
    @Override
    public int updateStatus(Long id, String status) {
        Station station = stationMapper.selectById(id);
        if (ObjectUtils.isEmpty(station)) {
            throw new ServiceException("要修改的站点不存在");
        }

        if (Objects.equals("1", status)) {
            //判断站点是否关联柜机
            if (ObjectUtils.isEmpty(station.getCabinetId())) {
                throw new ServiceException("请先关联柜机");
            }
        }
        station.setStatus(status);
        station.setUpdateBy(SecurityUtils.getUsername());
        station.setUpdateTime(new Date());
        return stationMapper.updateById(station);
    }

    /**
     * 生成柜机二维码
     *
     * @param cabinetNo
     * @return
     */
    @Override
    public BufferedImage generate(String cabinetNo, int width, int height) {
        //1.设置二维码生成参数
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 支持中文等特殊字符
        hints.put(EncodeHintType.ERROR_CORRECTION, com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.H); // 30%容错率
        hints.put(EncodeHintType.MARGIN, 1); // 二维码边框空白宽度

        //2.生成二维码矩阵数据
        MultiFormatWriter writer = new MultiFormatWriter();
        BitMatrix bitMatrix = null;
        try {
            bitMatrix = writer.encode(cabinetNo, BarcodeFormat.QR_CODE, width, height, hints);
        } catch (WriterException e) {
            throw new ServiceException(e.getMessage());
        }

        //3.转换为图像对象
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {

            for (int y = 0; y < height; y++) {

                image.setRGB(x, y, bitMatrix.get(x, y) ? Color.BLACK.getRGB() : Color.WHITE.getRGB());
            }
        }
        return image;
    }

}
